//
// Created by Mysher on 2021/5/7.
//

#ifndef TESTFFMPEG_DECODER_H
#define TESTFFMPEG_DECODER_H

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/log.h"

/**
* 解码器类型
*/
enum DecoderType {
    DecoderType_H264,   /** H264 */
    DecoderType_H265,   /** Hevc */
};

/**
 * 解码结果监听
 */
class IDecoderGotPictureListener {
public:
    virtual void onGotPicture(unsigned char *out_buffer, int out_buffer_size) = 0;
};

/**
 * 解码结果
 */
class CDecodeResult {
public:
    //解码内容宽度
    int m_mWidth;
    //解码内容高度
    int m_mHeight;
    //当前传入数据的有效长度
    int m_nLen;
    //解码是否得到帧
    //0 - 没有得到图像
    //1 - 得到图像
    int m_nGotPicture;
    //解码帧类型
    //0 - None
    //1 - I
    //2 - P
    //3 - B
    int m_nFrameType;
    //解码缓存长度
    int m_nOutBufferSize;
    //解码缓存
    unsigned char *m_ptOutBuffer;

    /**
     * 构造函数
     */
    CDecodeResult() {
        m_mWidth = 0;
        m_mHeight = 0;
        m_nLen = 0;
        m_nGotPicture = 0;
        m_nFrameType = 0;
        m_nOutBufferSize = 0;
        m_ptOutBuffer = NULL;
    }

    /**
     * 设置宽度和高度
     * @param w 宽度
     * @param h 高度
     */
    void setWH(int w, int h) {
        if(w != m_mWidth || h != m_mHeight) {
            if(m_ptOutBuffer != NULL) {
                delete m_ptOutBuffer;
            }

            m_mWidth = w;
            m_mHeight = h;
            m_nOutBufferSize = w * h * 3 / 2;
            m_ptOutBuffer = new unsigned char[m_nOutBufferSize];

        }
    }

    /**
     * 释放资源
     */
    void release() {
        if(m_ptOutBuffer != NULL) {
            delete m_ptOutBuffer;
        }

        m_mWidth = 0;
        m_mHeight = 0;
        m_nLen = 0;
        m_nGotPicture = 0;
        m_nFrameType = 0;
        m_nOutBufferSize = 0;
        m_ptOutBuffer = NULL;

    }


};


/**
 * 解码器
 */
class CDecoder {
public:
    /**
     * 初始化
     * @param type      解码器类型
     * @param listener  解码结果监听对象
     * @return          true-成功 false-失败
     */
    bool init(DecoderType type, IDecoderGotPictureListener *listener);

    /**
     * 解码
     * @param in_buffer         输入缓存
     * @param in_buffer_size    输入缓存长度
     * @param effect_len        输入缓存实际长度（有可能输入缓存包含多帧数据）
     * @return                  true-成功 false-失败
     */
    bool decode(unsigned char *in_buffer, int in_buffer_size, int &effect_len);

    /**
     * 初始化
     * @param type  解码器类型
     * @return      true-成功 false-失败
     */
    bool init(DecoderType type);

    /**
     * 解码
     * 需要使用getDecodeResult获取结果
     * @param in_buffer         输入缓存
     * @param in_buffer_size    输入缓存长度
     * @return                  true-成功 false-失败
     */
    bool decode(unsigned char *in_buffer, int in_buffer_size);

    /**
     * 获取解码结果
     * @return 解码结果
     * @see CDecodeResult
     */
    CDecodeResult* getDecodeResult() { return &m_decodeResult; }

    /**
     * 注销
     * <br>与init对应<br/>
     */
    void destroy();

private:
    IDecoderGotPictureListener *m_listener;
    AVCodec *pCodec;
    AVCodecContext *pCodecCtx= NULL;
    AVCodecParserContext *pCodecParserCtx=NULL;
    AVFrame	*pFrame;
    AVPacket *pPacket;
    int first_time=1;

public:
    CDecodeResult m_decodeResult;
};
}


#endif //TESTFFMPEG_DECODER_H
